import os
from datetime import datetime
from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory, send_file, jsonify
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from werkzeug.utils import secure_filename
from models import db, User, File, SchoolYear, Form, FormResponse
from config import Config
from functools import wraps
from openpyxl import Workbook, load_workbook
from io import BytesIO
from werkzeug.security import generate_password_hash

app = Flask(__name__)
app.config.from_object(Config)

# 管理员权限装饰器
def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated or not current_user.is_admin:
            flash('需要管理员权限')
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated_function

# 初始化扩展
db.init_app(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

# 确保上传目录存在
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

# 路由：主页
@app.route('/')
def index():
    return redirect(url_for('login'))

# 路由：注册
@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        real_name = request.form['real_name']
        phone = request.form['phone']
        department = request.form['department']
        confirm_password = request.form['confirm_password']
        
        # 表单验证
        if not username.isalnum() and '_' not in username:
            flash('用户名只能包含字母、数字和下划线')
            return redirect(url_for('register'))
        
        if len(password) < 6:
            flash('密码长度至少6位')
            return redirect(url_for('register'))
        
        if password != confirm_password:
            flash('两次输入的密码不一致')
            return redirect(url_for('register'))
        
        if User.query.filter_by(username=username).first():
            flash('用户名已存在')
            return redirect(url_for('register'))
        
        user = User(
            username=username,
            real_name=real_name,
            phone=phone,
            department=department,
            is_active=False
        )
        user.set_password(password)
        db.session.add(user)
        db.session.commit()
        
        flash('注册成功，请等待管理员审核后登录')
        return redirect(url_for('login'))
    
    return render_template('register.html')

# 路由：登录
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        
        if user and user.check_password(password) and (user.is_active or user.is_admin):
            login_user(user)
            return redirect(url_for('dashboard'))
        elif user and user.check_password(password) and not user.is_active:
            flash('账号待审核，请等待管理员审核')
        else:
            flash('用户名或密码错误')
        
    return render_template('login.html')

# 路由：登出
@app.route('/logout')
@login_required
def logout():
    logout_user()
    return redirect(url_for('login'))

# 路由：仪表板
@app.route('/dashboard')
@login_required
def dashboard():
    # 获取用户自己的文件和所有公开文件
    files = File.query.filter(
        (File.user_id == current_user.id) | (File.is_public == True)
    ).all()
    years = SchoolYear.query.order_by(SchoolYear.year.desc()).all()
    return render_template('dashboard.html', files=files, years=years)

# 路由：文件上传
@app.route('/upload', methods=['POST'])
@login_required
def upload_file():
    if 'file' not in request.files:
        flash('没有选择文件')
        return redirect(url_for('dashboard'))
    
    file = request.files['file']
    if file.filename == '':
        flash('没有选择文件')
        return redirect(url_for('dashboard'))
    
    if file:
        filename = secure_filename(file.filename)
        subject = request.form['subject']
        grade = request.form['grade']
        year = int(request.form['year'])
        description = request.form['description']
        
        # 生成唯一文件名
        unique_filename = f"{current_user.id}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}_{filename}"
        
        # 保存文件
        file.save(os.path.join(app.config['UPLOAD_FOLDER'], unique_filename))
        
        # 创建文件记录
        new_file = File(
            filename=unique_filename,
            original_filename=filename,
            subject=subject,
            grade=grade,
            year_id=year,
            description=description,
            is_public=request.form.get('is_public') == 'on',
            file_path=os.path.join(app.config['UPLOAD_FOLDER'], unique_filename),
            user_id=current_user.id
        )
        
        db.session.add(new_file)
        db.session.commit()
        
        flash('文件上传成功')
        return redirect(url_for('dashboard'))

# 路由：文件下载
@app.route('/download/<int:file_id>')
@login_required
def download_file(file_id):
    file = File.query.get_or_404(file_id)
    if file.user_id != current_user.id and not file.is_public:
        flash('没有权限下载此文件')
        return redirect(url_for('dashboard'))
    
    return send_from_directory(
        app.config['UPLOAD_FOLDER'],
        file.filename,
        as_attachment=True,
        download_name=file.original_filename
    )

# 创建管理员账号
def create_admin():
    admin = User.query.filter_by(username='admin').first()
    if not admin:
        admin = User(
            username='admin',
            real_name='系统管理员',
            phone='00000000000',
            department='管理员',
            is_admin=True,
            is_active=True
        )
        admin.set_password('admin03155663201')
        db.session.add(admin)
        db.session.commit()

# 管理用户表路由
@app.route('/admin/users')
@login_required
@admin_required
def admin_users():
    users = User.query.filter(User.username != 'admin').all()
    return render_template('admin/users.html', users=users)

# 导出用户信息路由
@app.route('/admin/users/export')
@login_required
@admin_required
def export_users():
    users = User.query.filter(User.username != 'admin').all()
    
    # 创建Excel文件
    wb = Workbook()
    ws = wb.active
    ws.title = "用户信息"
    
    # 写入表头
    headers = ['用户名', '姓名', '手机号码', '部门', '状态']
    ws.append(headers)
    
    # 写入数据
    for user in users:
        ws.append([
            user.username,
            user.real_name,
            user.phone,
            user.department,
            '已激活' if user.is_active else '待审核'
        ])
    
    # 保存到内存
    output = BytesIO()
    wb.save(output)
    output.seek(0)
    
    return send_file(
        output,
        mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        as_attachment=True,
        download_name=f'用户信息_{datetime.now().strftime("%Y%m%d")}.xlsx'
    )

# 下载用户导入模板
@app.route('/admin/users/template')
@login_required
@admin_required
def download_user_template():
    wb = Workbook()
    ws = wb.active
    ws.title = "用户信��"
    
    # 写入表头
    headers = ['用户名', '密码', '姓名', '手机号码', '部门']
    ws.append(headers)
    
    # 写入示例数据
    ws.append(['zhangsan', '123456', '张三', '13800138000', '教务处'])
    
    # 添加说明
    ws = wb.create_sheet("说明")
    ws.append(['字段', '说明', '要求'])
    ws.append(['用户名', '用户登录账号', '必填，只能包含字母、数字和下划线'])
    ws.append(['密码', '用户登录密码', '必填，长度至少6位'])
    ws.append(['姓名', '用户真实姓名', '必填'])
    ws.append(['手机号码', '用户联系电话', '必填，11位手机号'])
    ws.append(['部门', '用户所属部门', '必填'])
    
    output = BytesIO()
    wb.save(output)
    output.seek(0)
    
    return send_file(
        output,
        mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        as_attachment=True,
        download_name='用户导入模板.xlsx'
    )

# 批量导入用户
@app.route('/admin/users/import', methods=['POST'])
@login_required
@admin_required
def import_users():
    if 'file' not in request.files:
        flash('请选择文件')
        return redirect(url_for('admin_users'))
    
    file = request.files['file']
    if file.filename == '':
        flash('没有选择文件')
        return redirect(url_for('admin_users'))
    
    if not file.filename.endswith('.xlsx'):
        flash('请上传Excel文件(.xlsx)')
        return redirect(url_for('admin_users'))
    
    try:
        # 读取Excel文件
        wb = load_workbook(file)
        ws = wb.active
        
        # 获取表头
        headers = [cell.value for cell in ws[1]]
        required_headers = ['用户名', '密码', '姓名', '手机号码', '部门']
        
        # 验证表头
        if not all(header in headers for header in required_headers):
            flash('Excel文件格式不正确，请使用正确的模板')
            return redirect(url_for('admin_users'))
        
        success_count = 0
        error_messages = []
        
        # 从第二行开始读取数据
        for row in ws.iter_rows(min_row=2):
            username = row[headers.index('用户名')].value
            password = row[headers.index('密码')].value
            real_name = row[headers.index('姓名')].value
            phone = row[headers.index('手机号码')].value
            department = row[headers.index('部门')].value
            
            # 验证数据
            if not all([username, password, real_name, phone, department]):
                error_messages.append(f'行 {row[0].row}: 所有字段都必须填写')
                continue
            
            # 验证用户名是否已存在
            if User.query.filter_by(username=username).first():
                error_messages.append(f'行 {row[0].row}: 用户名 {username} 已存在')
                continue
            
            # 创建用户
            try:
                user = User(
                    username=username,
                    real_name=real_name,
                    phone=phone,
                    department=department,
                    is_active=True
                )
                user.set_password(password)
                db.session.add(user)
                success_count += 1
            except Exception as e:
                error_messages.append(f'行 {row[0].row}: {str(e)}')
        
        db.session.commit()
        
        # 显示导入结果
        if success_count > 0:
            flash(f'成功导入 {success_count} 个用户')
        if error_messages:
            flash('导入过程中出现以下错误：\n' + '\n'.join(error_messages))
        
    except Exception as e:
        flash(f'导入失败：{str(e)}')
    
    return redirect(url_for('admin_users'))

# 删除用户路由
@app.route('/admin/users/delete/<int:user_id>', methods=['POST'])
@login_required
@admin_required
def delete_user(user_id):
    user = User.query.get_or_404(user_id)
    if user.username != 'admin':
        # 删除用户的所有文件
        for file in user.files:
            try:
                os.remove(file.file_path)
            except:
                pass
        db.session.delete(user)
        db.session.commit()
        flash(f'用户 {user.username} 已删除')
    return redirect(url_for('admin_users'))

# 管理员审核用户路由
@app.route('/admin/users/approve/<int:user_id>', methods=['POST'])
@login_required
@admin_required
def approve_user(user_id):
    user = User.query.get_or_404(user_id)
    if user.username != 'admin':
        user.is_active = True
        db.session.commit()
        flash(f'用户 {user.username} 已审核通过')
    return redirect(url_for('admin_users'))

# 管理员修改用户密码路由
@app.route('/admin/users/change_password/<int:user_id>', methods=['POST'])
@login_required
@admin_required
def change_user_password(user_id):
    user = User.query.get_or_404(user_id)
    if user.username != 'admin':
        new_password = request.form['new_password']
        confirm_password = request.form['confirm_password']
        
        if len(new_password) < 6:
            flash('密码长度至少6位')
            return redirect(url_for('admin_users'))
        
        if new_password != confirm_password:
            flash('两次输入的密码不一致')
            return redirect(url_for('admin_users'))
        
        user.set_password(new_password)
        db.session.commit()
        flash(f'用户 {user.username} 的密码已修改')
    return redirect(url_for('admin_users'))

# 年份管理路由
@app.route('/admin/years')
@login_required
@admin_required
def manage_years():
    years = SchoolYear.query.order_by(SchoolYear.year.desc()).all()
    return render_template('admin/years.html', years=years)

# 添加年份路由
@app.route('/admin/years/add', methods=['POST'])
@login_required
@admin_required
def add_year():
    year = request.form.get('year', type=int)
    if year:
        if not SchoolYear.query.filter_by(year=year).first():
            new_year = SchoolYear(year=year)
            db.session.add(new_year)
            db.session.commit()
            flash(f'{year}年添加成功')
        else:
            flash(f'{year}年已存在')
    return redirect(url_for('manage_years'))

# 切换年份状态路由
@app.route('/admin/years/toggle/<int:year_id>', methods=['POST'])
@login_required
@admin_required
def toggle_year(year_id):
    year = SchoolYear.query.get_or_404(year_id)
    year.is_active = not year.is_active
    db.session.commit()
    flash(f'{year.year}年状态已更新')
    return redirect(url_for('manage_years'))

# 文件可见性管理路由
@app.route('/admin/visibility')
@login_required
@admin_required
def manage_visibility():
    files = File.query.all()
    all_public = all(file.is_public for file in files) if files else False
    return render_template('admin/visibility.html', files=files, all_public=all_public)

# 设置所有文件可见性路由
@app.route('/admin/visibility/set_all', methods=['POST'])
@login_required
@admin_required
def set_all_visibility():
    is_public = request.form.get('is_public') == 'on'
    File.query.update({File.is_public: is_public})
    db.session.commit()
    flash('所有文件可见性已更新')
    return redirect(url_for('manage_visibility'))

# 切换单个文件可见性路由
@app.route('/admin/visibility/toggle/<int:file_id>', methods=['POST'])
@login_required
@admin_required
def toggle_file_visibility(file_id):
    file = File.query.get_or_404(file_id)
    file.is_public = not file.is_public
    db.session.commit()
    flash(f'文件 {file.original_filename} 的可见性已更新')
    return redirect(url_for('manage_visibility'))

# 表单列表路由
@app.route('/forms')
@login_required
def form_list():
    forms = Form.query.filter_by(is_active=True).all()
    return render_template('forms/list.html', forms=forms)

# 创建表单路由（仅管理员）
@app.route('/forms/create', methods=['GET', 'POST'])
@login_required
@admin_required
def create_form():
    if request.method == 'POST':
        try:
            data = request.get_json()
            if not data.get('title'):
                return jsonify({'success': False, 'message': '表单标题不能为空'})
            if not data.get('fields'):
                return jsonify({'success': False, 'message': '至少需要添加一个字段'})
            
            form_data = {
                'title': data['title'],
                'description': data.get('description', ''),
                'fields': data['fields'],
                'creator_id': current_user.id,
                'allow_multi_submit': data.get('allow_multi_submit', True)
            }
            
            new_form = Form(**form_data)
            db.session.add(new_form)
            db.session.commit()
            
            return jsonify({
                'success': True,
                'message': '表单创建成功',
                'form_id': new_form.id
            })
        except Exception as e:
            db.session.rollback()
            return jsonify({
                'success': False,
                'message': f'创建表单失败: {str(e)}'
            }), 500
    
    return render_template('forms/create.html')

# 填写表单路由
@app.route('/forms/<int:form_id>/fill', methods=['GET', 'POST'])
@login_required
def fill_form(form_id):
    form = Form.query.get_or_404(form_id)
    if not form.is_active:
        flash('此表单已关闭')
        return redirect(url_for('form_list'))
    
    # 获取用户的所有回答
    responses = FormResponse.query.filter_by(
        form_id=form_id,
        user_id=current_user.id
    ).order_by(FormResponse.submit_time.desc()).all()
    
    if request.method == 'POST':
        # 创建新的回答记录
        response = FormResponse(
            form_id=form_id,
            user_id=current_user.id
        )
        
        response_data = request.form.to_dict()
        response.data = response_data
        db.session.add(response)
        db.session.commit()
        flash('表单提交成功')
        return redirect(url_for('form_list'))
    
    return render_template('forms/fill.html', form=form, responses=responses)

# 表单结果导出路由（仅管理员）
@app.route('/forms/<int:form_id>/export')
@login_required
@admin_required
def export_form_results(form_id):
    form = Form.query.get_or_404(form_id)
    responses = FormResponse.query.filter_by(form_id=form_id).all()
    
    # 创建Excel文件
    wb = Workbook()
    ws = wb.active
    ws.title = form.title
    
    # 写入表头
    headers = ['提交时间', '用户名', '姓名', '部门'] + [field['label'] for field in form.fields]
    ws.append(headers)
    
    # 写入数据
    for response in responses:
        row = [
            response.submit_time.strftime('%Y-%m-%d %H:%M:%S'),
            response.user.username,
            response.user.real_name,
            response.user.department
        ]
        for field in form.fields:
            row.append(response.data.get(field['name'], ''))
        ws.append(row)
    
    # 保存到内存
    output = BytesIO()
    wb.save(output)
    output.seek(0)
    
    return send_file(
        output,
        mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        as_attachment=True,
        download_name=f'{form.title}_结果_{datetime.now().strftime("%Y%m%d")}.xlsx'
    )

# 删除表单路由（仅管理员）
@app.route('/forms/<int:form_id>/delete', methods=['POST'])
@login_required
@admin_required
def delete_form(form_id):
    form = Form.query.get_or_404(form_id)
    
    # 删除所有相关的表单响应
    FormResponse.query.filter_by(form_id=form_id).delete()
    
    # 删除表单
    db.session.delete(form)
    db.session.commit()
    
    flash('表单已删除')
    return redirect(url_for('form_list'))

if __name__ == '__main__':
    with app.app_context():
        # 只创建表（如果不存在）
        db.create_all()
        
        # 检查是否需要创建管理员账号
        try:
            admin = User.query.filter_by(username='admin').first()
            if not admin:
                create_admin()  # 只在管理员不存在时创建
                print("管理员账号创建成功！")
                print("用户名: admin")
                print("密码: admin03155663201")
        except Exception as e:
            print(f"Error creating admin: {e}")
    app.run(host='0.0.0.0', port=8002, debug=True) 